home *** CD-ROM | disk | FTP | other *** search
/ Workbench Add-On / Workbench Add-On - Volume 1.iso / BBS-Archive / Comm / AmiTCP30b2.lha / src / util / portmap / portmap.c next >
C/C++ Source or Header  |  1994-05-03  |  12KB  |  498 lines

  1. RCS_ID_C="$Id: portmap.c,v 3.9 1994/05/02 19:52:55 jraja Exp $";
  2. /*
  3.  * portmap.c -- implements the program, version to port number mapping for rpc
  4.  */
  5.  
  6. #include "portmap_rev.h"
  7.  
  8. static const char version[] = VERSTAG
  9. " Copyright © 1994 AmiTCP/IP Group, <amitcp-group@hut.fi>\n"
  10. "Helsinki University of Technology, Finland.\n"
  11. "Copyright © 1990 The Regents of the University of California.\n"
  12. "All rights reserved.\n";
  13.  
  14. /****** netutil.doc/portmap *************************************************
  15.     NAME
  16.         portmap - DARPA port to RPC program number mapper
  17.  
  18.     SYNOPSIS
  19.         AmiTCP:bin/portmap
  20.  
  21.     DESCRIPTION
  22.         `portmap' is a server that converts RPC program numbers into DARPA
  23.         protocol port numbers.  It must be running in order to make RPC
  24.         calls.  When an RPC server is started, it will tell `portmap' what
  25.         port number it is listening to, and what RPC program numbers it is
  26.         prepared to serve.  When a client wishes to make an RPC call to a
  27.         given program number, it will first contact `portmap' on the
  28.         server machine to determine the port number where RPC packets
  29.         should be sent.  Normally, standard RPC servers are started by
  30.         `inetd', so `portmap' must be started before `inetd' is invoked.
  31.  
  32.     SEE ALSO
  33.         netutil.doc/rpcinfo
  34.  
  35.     BUGS
  36.         If `portmap' crashes, all servers must be restarted.
  37.  
  38. *****************************************************************************
  39. */
  40.  
  41. /*
  42.  * @(#)portmap.c 5.4 (Berkeley) 4/19/91
  43.  * @(#)portmap.c 2.3 88/08/11 4.0 RPCSRC
  44.  * @(#)portmap.c 1.32 87/08/06 Copyr 1984 Sun Micro";
  45.  */
  46.  
  47. #include <rpc/rpc.h>
  48. #include <rpc/pmap_prot.h>
  49. #include <sys/syslog.h>
  50. #include <sys/socket.h>
  51. #include <sys/ioctl.h>
  52. #include <netdb.h>
  53. #include <errno.h>
  54. #include <stdio.h>
  55. #include <stdlib.h>
  56. #include <string.h>
  57. #include <signal.h>
  58.  
  59. void reg_service(struct svc_req *rqstp, SVCXPRT *xprt);
  60. static void callit(struct svc_req *rqstp, SVCXPRT *xprt);
  61.  
  62. struct pmaplist *pmaplist;
  63. int debugging = 0;
  64.  
  65. main(int argc, char **argv)
  66. {
  67.     SVCXPRT *xprt;
  68.     int sock, c;
  69.     struct sockaddr_in addr = { 0 };
  70.     int len = sizeof(struct sockaddr_in);
  71.     register struct pmaplist *pml;
  72.  
  73.     signal(SIGINT, SIG_IGN); /* Prevent ANSI Signal handling */
  74.  
  75.     while ((c = getopt(argc, argv, "d")) != EOF) {
  76.         switch (c) {
  77.  
  78.         case 'd':
  79.             debugging = 1;
  80.             break;
  81.  
  82.         default:
  83.             (void) fprintf(stderr, "usage: %s [-d]\n", argv[0]);
  84.             exit(1);
  85.         }
  86.     }
  87.  
  88.     openlog("portmap", debugging ? LOG_PID | LOG_PERROR : LOG_PID,
  89.         LOG_DAEMON);
  90. #ifndef amigados
  91.     if (!debugging && daemon(0, 0)) {
  92.         (void) fprintf(stderr, "portmap: fork: %s", strerror(errno));
  93.         exit(1);
  94.     }
  95. #else
  96.     /*
  97.      * We could probably detach here, but don't bother now...
  98.      */
  99. #endif
  100.  
  101.     if ((sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) < 0) {
  102.         syslog(LOG_ERR, "cannot create udp socket: %m");
  103.         exit(1);
  104.     }
  105.  
  106.     addr.sin_addr.s_addr = 0;
  107.     addr.sin_family = AF_INET;
  108.     addr.sin_port = htons(PMAPPORT);
  109.     if (bind(sock, (struct sockaddr *)&addr, len) != 0) {
  110.         syslog(LOG_ERR, "cannot bind udp: %m");
  111.         exit(1);
  112.     }
  113.  
  114.     if ((xprt = svcudp_create(sock)) == (SVCXPRT *)NULL) {
  115.         syslog(LOG_ERR, "couldn't do udp_create");
  116.         exit(1);
  117.     }
  118.     /* make an entry for ourself */
  119.     pml = (struct pmaplist *)malloc((u_int)sizeof(struct pmaplist));
  120.     pml->pml_next = 0;
  121.     pml->pml_map.pm_prog = PMAPPROG;
  122.     pml->pml_map.pm_vers = PMAPVERS;
  123.     pml->pml_map.pm_prot = IPPROTO_UDP;
  124.     pml->pml_map.pm_port = PMAPPORT;
  125.     pmaplist = pml;
  126.  
  127.     if ((sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) < 0) {
  128.         syslog(LOG_ERR, "cannot create tcp socket: %m");
  129.         exit(1);
  130.     }
  131.     if (bind(sock, (struct sockaddr *)&addr, len) != 0) {
  132.         syslog(LOG_ERR, "cannot bind udp: %m");
  133.         exit(1);
  134.     }
  135.     if ((xprt = svctcp_create(sock, RPCSMALLMSGSIZE, RPCSMALLMSGSIZE))
  136.         == (SVCXPRT *)NULL) {
  137.         syslog(LOG_ERR, "couldn't do tcp_create");
  138.         exit(1);
  139.     }
  140.     /* make an entry for ourself */
  141.     pml = (struct pmaplist *)malloc((u_int)sizeof(struct pmaplist));
  142.     pml->pml_map.pm_prog = PMAPPROG;
  143.     pml->pml_map.pm_vers = PMAPVERS;
  144.     pml->pml_map.pm_prot = IPPROTO_TCP;
  145.     pml->pml_map.pm_port = PMAPPORT;
  146.     pml->pml_next = pmaplist;
  147.     pmaplist = pml;
  148.  
  149.     (void)svc_register(xprt, PMAPPROG, PMAPVERS, reg_service, FALSE);
  150.  
  151.     svc_run();
  152.     syslog(LOG_ERR, "svc_run returned unexpectedly");
  153.     exit(0);
  154. }
  155.  
  156. /*
  157.  * Overrides the strlib perror
  158.  */
  159. void
  160. perror(const char *what)
  161. {
  162.     syslog(LOG_ERR, "%s: %m", what);
  163. }
  164.  
  165. static struct pmaplist *
  166. find_service(u_long prog, u_long vers, u_long prot)
  167. {
  168.     register struct pmaplist *hit = NULL;
  169.     register struct pmaplist *pml;
  170.  
  171.     for (pml = pmaplist; pml != NULL; pml = pml->pml_next) {
  172.         if ((pml->pml_map.pm_prog != prog) ||
  173.             (pml->pml_map.pm_prot != prot))
  174.             continue;
  175.         hit = pml;
  176.         if (pml->pml_map.pm_vers == vers)
  177.             break;
  178.     }
  179.     return (hit);
  180. }
  181.  
  182. /* 
  183.  * 1 OK, 0 not
  184.  */
  185. void
  186. reg_service(struct svc_req *rqstp, SVCXPRT *xprt)
  187. {
  188.     struct pmap reg;
  189.     struct pmaplist *pml, *prevpml, *fnd;
  190.     int ans, port;
  191.     caddr_t t;
  192.     
  193.     if (debugging)
  194.         (void) fprintf(stderr, "server: about do a switch\n");
  195.     switch (rqstp->rq_proc) {
  196.  
  197.     case PMAPPROC_NULL:
  198.         /*
  199.          * Null proc call
  200.          */
  201.         if (!svc_sendreply(xprt, xdr_void, (caddr_t)0) && debugging) {
  202.             exit(20);
  203.         }
  204.         break;
  205.  
  206.     case PMAPPROC_SET:
  207.         /*
  208.          * Set a program,version to port mapping
  209.          */
  210.         if (!svc_getargs(xprt, xdr_pmap, ®))
  211.             svcerr_decode(xprt);
  212.         else {
  213.             /*
  214.              * check to see if already used
  215.              * find_service returns a hit even if
  216.              * the versions don't match, so check for it
  217.              */
  218.             fnd = find_service(reg.pm_prog, reg.pm_vers, reg.pm_prot);
  219.             if (fnd && fnd->pml_map.pm_vers == reg.pm_vers) {
  220.                 if (fnd->pml_map.pm_port == reg.pm_port) {
  221.                     ans = 1;
  222.                     goto done;
  223.                 }
  224.                 else {
  225.                     ans = 0;
  226.                     goto done;
  227.                 }
  228.             } else {
  229.                 /* 
  230.                  * add to END of list
  231.                  */
  232.                 pml = (struct pmaplist *)
  233.                     malloc((u_int)sizeof(struct pmaplist));
  234.                 pml->pml_map = reg;
  235.                 pml->pml_next = 0;
  236.                 if (pmaplist == 0) {
  237.                     pmaplist = pml;
  238.                 } else {
  239.                     for (fnd= pmaplist; fnd->pml_next != 0;
  240.                         fnd = fnd->pml_next);
  241.                     fnd->pml_next = pml;
  242.                 }
  243.                 ans = 1;
  244.             }
  245.         done:
  246.             if ((!svc_sendreply(xprt, xdr_long, (caddr_t)&ans)) &&
  247.                 debugging) {
  248.                 (void) fprintf(stderr, "svc_sendreply\n");
  249.                 exit(20);
  250.             }
  251.         }
  252.         break;
  253.  
  254.     case PMAPPROC_UNSET:
  255.         /*
  256.          * Remove a program,version to port mapping.
  257.          */
  258.         if (!svc_getargs(xprt, xdr_pmap, ®))
  259.             svcerr_decode(xprt);
  260.         else {
  261.             ans = 0;
  262.             for (prevpml = NULL, pml = pmaplist; pml != NULL; ) {
  263.                 if ((pml->pml_map.pm_prog != reg.pm_prog) ||
  264.                     (pml->pml_map.pm_vers != reg.pm_vers)) {
  265.                     /* both pml & prevpml move forwards */
  266.                     prevpml = pml;
  267.                     pml = pml->pml_next;
  268.                     continue;
  269.                 }
  270.                 /* found it; pml moves forward, prevpml stays */
  271.                 ans = 1;
  272.                 t = (caddr_t)pml;
  273.                 pml = pml->pml_next;
  274.                 if (prevpml == NULL)
  275.                     pmaplist = pml;
  276.                 else
  277.                     prevpml->pml_next = pml;
  278.                 free(t);
  279.             }
  280.             if ((!svc_sendreply(xprt, xdr_long, (caddr_t)&ans)) &&
  281.                 debugging) {
  282.                 (void) fprintf(stderr, "svc_sendreply\n");
  283.                 exit(20);
  284.             }
  285.         }
  286.         break;
  287.  
  288.     case PMAPPROC_GETPORT:
  289.         /*
  290.          * Lookup the mapping for a program,version and return its port
  291.          */
  292.         if (!svc_getargs(xprt, xdr_pmap, ®))
  293.             svcerr_decode(xprt);
  294.         else {
  295.             fnd = find_service(reg.pm_prog, reg.pm_vers, reg.pm_prot);
  296.             if (fnd)
  297.                 port = fnd->pml_map.pm_port;
  298.             else
  299.                 port = 0;
  300.             if ((!svc_sendreply(xprt, xdr_long, (caddr_t)&port)) &&
  301.                 debugging) {
  302.                 (void) fprintf(stderr, "svc_sendreply\n");
  303.                 exit(20);
  304.             }
  305.         }
  306.         break;
  307.  
  308.     case PMAPPROC_DUMP:
  309.         /*
  310.          * Return the current set of mapped program,version
  311.          */
  312.         if (!svc_getargs(xprt, xdr_void, NULL))
  313.             svcerr_decode(xprt);
  314.         else {
  315.             if ((!svc_sendreply(xprt, xdr_pmaplist,
  316.                 (caddr_t)&pmaplist)) && debugging) {
  317.                 (void) fprintf(stderr, "svc_sendreply\n");
  318.                 exit(20);
  319.             }
  320.         }
  321.         break;
  322.  
  323.     case PMAPPROC_CALLIT:
  324.         /*
  325.          * Calls a procedure on the local machine.  If the requested
  326.          * procedure is not registered this procedure does not return
  327.          * error information!!
  328.          * This procedure is only supported on rpc/udp and calls via 
  329.          * rpc/udp.  It passes null authentication parameters.
  330.          */
  331.         callit(rqstp, xprt);
  332.         break;
  333.  
  334.     default:
  335.         svcerr_noproc(xprt);
  336.         break;
  337.     }
  338. }
  339.  
  340.  
  341. /*
  342.  * Stuff for the rmtcall service
  343.  */
  344. #define ARGSIZE 9000
  345.  
  346. struct encap_parms {
  347.     u_int arglen;
  348.     char *args;
  349. };
  350.  
  351. static bool_t XDRFUN
  352. xdr_encap_parms(XDR *xdrs, struct encap_parms *epp)
  353. {
  354.  
  355.     return (xdr_bytes(xdrs, &(epp->args), &(epp->arglen), ARGSIZE));
  356. }
  357.  
  358. struct rmtcallargs {
  359.     u_long    rmt_prog;
  360.     u_long    rmt_vers;
  361.     u_long    rmt_port;
  362.     u_long    rmt_proc;
  363.     struct encap_parms rmt_args;
  364. };
  365.  
  366. static bool_t XDRFUN
  367. xdr_rmtcall_args(register XDR *xdrs, register struct rmtcallargs *cap)
  368. {
  369.  
  370.     /* does not get a port number */
  371.     if (xdr_u_long(xdrs, &(cap->rmt_prog)) &&
  372.         xdr_u_long(xdrs, &(cap->rmt_vers)) &&
  373.         xdr_u_long(xdrs, &(cap->rmt_proc))) {
  374.         return (xdr_encap_parms(xdrs, &(cap->rmt_args)));
  375.     }
  376.     return (FALSE);
  377. }
  378.  
  379. static bool_t XDRFUN
  380. xdr_rmtcall_result(register XDR *xdrs, register struct rmtcallargs *cap)
  381. {
  382.     if (xdr_u_long(xdrs, &(cap->rmt_port)))
  383.         return (xdr_encap_parms(xdrs, &(cap->rmt_args)));
  384.     return (FALSE);
  385. }
  386.  
  387. /*
  388.  * only worries about the struct encap_parms part of struct rmtcallargs.
  389.  * The arglen must already be set!!
  390.  */
  391. static bool_t XDRFUN
  392. xdr_opaque_parms(XDR *xdrs, struct rmtcallargs *cap)
  393. {
  394.  
  395.     return (xdr_opaque(xdrs, cap->rmt_args.args, cap->rmt_args.arglen));
  396. }
  397.  
  398. /*
  399.  * This routine finds and sets the length of incoming opaque parameters
  400.  * and then calls xdr_opaque_parms.
  401.  */
  402. static bool_t XDRFUN 
  403. xdr_len_opaque_parms(register XDR *xdrs, struct rmtcallargs *cap)
  404. {
  405.     register u_int beginpos, lowpos, highpos, currpos, pos;
  406.  
  407.     beginpos = lowpos = pos = xdr_getpos(xdrs);
  408.     highpos = lowpos + ARGSIZE;
  409.     while ((int)(highpos - lowpos) >= 0) {
  410.         currpos = (lowpos + highpos) / 2;
  411.         if (xdr_setpos(xdrs, currpos)) {
  412.             pos = currpos;
  413.             lowpos = currpos + 1;
  414.         } else {
  415.             highpos = currpos - 1;
  416.         }
  417.     }
  418.     xdr_setpos(xdrs, beginpos);
  419.     cap->rmt_args.arglen = pos - beginpos;
  420.     return (xdr_opaque_parms(xdrs, cap));
  421. }
  422.  
  423. /*
  424.  * Call a remote procedure service
  425.  * This procedure is very quiet when things go wrong.
  426.  * The proc is written to support broadcast rpc.  In the broadcast case,
  427.  * a machine should shut-up instead of complain, less the requestor be
  428.  * overrun with complaints at the expense of not hearing a valid reply ...
  429.  *
  430.  * This now forks so that the program & process that it calls can call 
  431.  * back to the portmapper.
  432.  */
  433. static void
  434. callit(struct svc_req *rqstp, SVCXPRT *xprt)
  435. {
  436.     struct rmtcallargs a;
  437.     struct pmaplist *pml;
  438.     u_short port;
  439.     struct sockaddr_in me;
  440. #ifndef amigados /* forking not supported */
  441.     int pid;
  442. #endif
  443.     int so = -1;
  444.     CLIENT *client;
  445.     struct authunix_parms *au = (struct authunix_parms *)rqstp->rq_clntcred;
  446.     struct timeval timeout;
  447.     char buf[ARGSIZE];
  448.  
  449.     timeout.tv_sec = 5;
  450.     timeout.tv_usec = 0;
  451.     a.rmt_args.args = buf;
  452.     if (!svc_getargs(xprt, xdr_rmtcall_args, &a))
  453.         return;
  454.     if ((pml = find_service(a.rmt_prog, a.rmt_vers,
  455.         (u_long)IPPROTO_UDP)) == NULL)
  456.         return;
  457. #ifndef amigados /* forking not supported */
  458.     /*
  459.      * fork a child to do the work.  Parent immediately returns.
  460.      * Child exits upon completion.
  461.      */
  462.     if ((pid = fork()) != 0) {
  463.         if (pid < 0)
  464.             syslog(LOG_ERR, "CALLIT (prog %lu): fork: %m",
  465.                 a.rmt_prog);
  466.         return;
  467.     }
  468. #endif
  469.     port = pml->pml_map.pm_port;
  470.     get_myaddress(&me);
  471.     me.sin_port = htons(port);
  472.     client = clntudp_create(&me, a.rmt_prog, a.rmt_vers, timeout, &so);
  473.     if (client != (CLIENT *)NULL) {
  474.         if (rqstp->rq_cred.oa_flavor == AUTH_UNIX) {
  475.             client->cl_auth = authunix_create(au->aup_machname,
  476.                au->aup_uid, au->aup_gid, au->aup_len, au->aup_gids);
  477.         }
  478.         a.rmt_port = (u_long)port;
  479.         if (clnt_call(client, a.rmt_proc, xdr_opaque_parms, &a,
  480.             xdr_len_opaque_parms, &a, timeout) == RPC_SUCCESS) {
  481.             svc_sendreply(xprt, xdr_rmtcall_result, (caddr_t)&a);
  482.         }
  483.         AUTH_DESTROY(client->cl_auth);
  484.         clnt_destroy(client);
  485.     }
  486.     (void)CloseSocket(so);
  487.     exit(0);
  488. }
  489.  
  490. #ifndef amigados /* forking not supported */
  491. void
  492. reap()
  493. {
  494.     while (wait3((int *)NULL, WNOHANG, (struct rusage *)NULL) > 0);
  495. }
  496. #endif
  497.